package cn.edu.xmu.orderpayment.payment.Service;

import cn.edu.xmu.oomall.core.util.ReturnNo;
import cn.edu.xmu.oomall.core.util.ReturnObject;
import cn.edu.xmu.oomall.core.util.Common;
import cn.edu.xmu.orderpayment.payment.Dao.ErrorAccountDao;
import cn.edu.xmu.orderpayment.payment.Dao.PaymentDao;
import cn.edu.xmu.orderpayment.payment.Dao.PaymentPatternDao;
import cn.edu.xmu.orderpayment.payment.Dao.RefundDao;
import cn.edu.xmu.orderpayment.payment.model.bo.ErrorAccount;
import cn.edu.xmu.orderpayment.payment.model.bo.Payment;
import cn.edu.xmu.orderpayment.payment.model.bo.PaymentPattern;
import cn.edu.xmu.orderpayment.payment.model.bo.Refund;
import cn.edu.xmu.orderpayment.payment.model.vo.*;
import cn.edu.xmu.orderpayment.payment.util.PayMentPatternLoader;
import cn.edu.xmu.orderpayment.payment.util.baseobject.BillDownloadInfo;
import cn.edu.xmu.orderpayment.payment.util.baseobject.Transaction;
import cn.edu.xmu.orderpayment.payment.util.paypattern.BasePaymentPattern;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import static cn.edu.xmu.orderpayment.payment.util.baseobject.Transaction.TransactionType.PAY;
import static cn.edu.xmu.privilegegateway.annotation.util.Common.cloneVo;


@Service
public class ReconciliationService {

    private Logger logger = LoggerFactory.getLogger(ReconciliationService.class);

    @Autowired
    @Lazy
    private PayMentPatternLoader payMentPatternLoader;

    @Autowired
    private PaymentPatternDao paymentPatternDao;

    @Autowired
    private PaymentDao paymentDao;

    @Autowired
    private RefundDao refundDao;

    @Autowired
    private PaymentPatternService paymentPatternService;

    @Autowired
    private PaymentService paymentService;

    @Autowired
    private RefundService refundService;

    @Autowired
    private ErrorAccountService errorAccountService;

    @Autowired
    private ErrorAccountDao errorAccountDao;

    @Autowired
    private ReconciliationService reconciliationService;

    /**
     * 对账
     * 对给定的时间范围内的账单进行对账
     * 返回正确条数、错误条数、第三方流水多出条数
     * 需调用第三方支付平台接口
     *
     * @return
     * @author wang xusheng
     */
    @Transactional(rollbackFor = Exception.class)
    public ReturnObject reconciliation(Long loginId, String loginName, ZonedDateTime beginTime, ZonedDateTime endTime) {
//        LocalDateTime beginTime = beginZonedTime.withZoneSameInstant(ZoneId.systemDefault()).toLocalDateTime();
//        LocalDateTime endTime = endZonedTime.withZoneSameInstant(ZoneId.systemDefault()).toLocalDateTime();
        long extra = 0L, error = 0L, success = 0L;
        List<Transaction> payTransactions = new ArrayList<>();
        List<Transaction> refundTransactions = new ArrayList<>();
        //由于获取账单只与日期有关因此以LocalDate传参，计算时间段包含的日期数，
        LocalDate beginDate = LocalDate.parse(beginTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
        LocalDate endDate = LocalDate.parse(endTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
        //加1是因为durationDays是时间段包含的日期数，而不是相差的天数
        Long durationDays = endDate.toEpochDay() - beginDate.toEpochDay() + 1;
        LocalDate billDate = beginDate;
        List<PaymentPatternRetVo> paymentPatterns = (List<PaymentPatternRetVo>) paymentPatternDao.getPayPatternByState(null).getData();

        //从beginDate开始，直到endDate，不断获取当日对应支付方式的账单
        while (durationDays > 0) {
            for (PaymentPatternRetVo payPatternRetVo : paymentPatterns) {
                BasePaymentPattern paymentPattern = getBasePayPatternById(payPatternRetVo.getId());
                BillDownloadInfo billDownloadInfo = paymentPattern.getBillDownloadUrl(billDate);
                List<Transaction> paymentPatternTransactions = paymentPattern.getTransactionsFromCSV(billDownloadInfo.getDownloadUrl());
                for (Transaction transaction : paymentPatternTransactions) {
                    if (transaction.getTransactionType().equals(PAY)) {
                        payTransactions.add(transaction);
                    } else {
                        refundTransactions.add(transaction);
                    }
                }
            }
            billDate.plusDays(1);
            durationDays--;
        }

        try {
            //获取支付单、退款单以及第三方支付平台账单
            List<Payment> payments = (List<Payment>) paymentDao.getPaymentsByTime(beginTime, endTime).getData();
            for (Payment payment : payments) {
                boolean reconciliation = false;
                for (Transaction transaction : payTransactions) {
                    if (transaction.getRequestSn().equals(String.valueOf(payment.getId()))) {
                        reconciliation = true;
                        //对账成功
                        if (payment.getActualAmount().equals(transaction.getAmount())) {
                            success++;
                            payment.setState(Payment.State.RECONCILIATION_COMPLETED);
                            payment.setAdjustId(loginId);
                            payment.setAdjustName(loginName);
                            payment.setAdjustTime(LocalDateTime.now());
                            paymentDao.setPaymentReconciled(payment);
                        }
                        //对账失败
                        else {
                            error++;
                            ErrorAccount errorAccount = new ErrorAccount();
                            errorAccount.setTradeSn(transaction.getTradeSn());
                            errorAccount.setPatternId(payment.getPatternId());
                            errorAccount.setDocumentId(payment.getDocumentId());
                            errorAccount.setIncome(transaction.getAmount());
                            errorAccount.setState(ErrorAccount.State.TOBEPAID.getCode());
                            errorAccount.setTime(transaction.getTransactionTime());
                            errorAccount.setDescr(payment.getDescr());
                            errorAccountDao.inserterrorAccount(errorAccount, loginId, loginName);
                        }
                        break;
                    }
                }
                //找不到对应的transcation，长账
                if (!reconciliation) {
                    extra++;
                }
            }
            List<Refund> refunds = (List<Refund>) refundDao.getRefundsByTime(beginTime, endTime).getData();
            for (Refund refund : refunds) {
                boolean reconciliation = false;
                for (Transaction transaction : refundTransactions) {
                    if (String.valueOf(refund.getId()).equals(transaction.getRequestSn())) {
                        reconciliation = true;
                        //对账成功，修改为已对账
                        if (refund.getAmount().equals(transaction.getAmount())) {
                            success++;
                            refund.setState(Refund.State.RECONCILIATION_COMPLETED);
                            refund.setAdjustId(loginId);
                            refund.setAdjustName(loginName);
                            refund.setAdjustTime(LocalDateTime.now());
                            refundDao.setRefundReconciled(refund);
                        }
                        //对账失败，记录到错账
                        else {
                            error++;
                            ErrorAccount errorAccount = new ErrorAccount();
                            errorAccount.setTradeSn(transaction.getTradeSn());
                            errorAccount.setPatternId(refund.getPatternId());
                            errorAccount.setDocumentId(((Payment) paymentDao.selectPaymentInfoByPrimaryKey(refund.getPaymentId()).getData()).getDocumentId());
                            errorAccount.setExpenditure(transaction.getAmount());
                            errorAccount.setState(ErrorAccount.State.TOBEPAID.getCode());
                            errorAccount.setTime(transaction.getTransactionTime());
                            errorAccount.setDescr(refund.getDescr());
                            errorAccountDao.inserterrorAccount(errorAccount, loginId, loginName);
                        }
                    }
                }
                //找不到对应的transcation，长账
                if (!reconciliation) {
                    extra++;
                }
            }
            return new ReturnObject(new ReconciliationRetVo(success, error, extra));
        } catch (Exception e) {
            return new ReturnObject(ReturnNo.INTERNAL_SERVER_ERR, e.getMessage() + "--11");
        }
    }

    private BasePaymentPattern getBasePayPatternById(Long id) {
        try {
            ReturnObject<PaymentPattern> ret = paymentPatternDao.getPaymentPatternById(id);
            if (ret.getData() == null) return null;
            BasePaymentPattern paymentPattern = payMentPatternLoader.getPaymentPatternByClassName(ret.getData().getClassName());
            return paymentPattern;
        } catch (Exception e) {
            logger.error(e.getMessage());
            return null;
        }
    }


}
